/**
 * 控制流程 https://book.kotlincn.net/text/d-control-flow.html
 */

/**
 * 条件与循环
 */
fun main101() {
    /**
     * If 表达式
     * 在 Kotlin 中，if 是一个表达式：它会返回一个值。
     * 因此就不需要三元运算符（条件 ? 然后 : 否则），因为普通的 if 就能胜任这个角色。
     */
    val a = 2
    val b = 3

    var max = a
    if (a < b) max = b

    // With else
    if (a > b) {
        max = a
    } else {
        max = b
    }

    // 作为表达式
    max = if (a > b) a else b       //★★★

    // You can also use `else if` in expressions:
    val maxLimit = 1
    val maxOrLimit = if (maxLimit > a) maxLimit else if (a > b) a else b

    println("max is $max")
    println("maxOrLimit is $maxOrLimit")


    /**
     * if 表达式的分支可以是代码块，这种情况最后的表达式作为该块的值：
     */
    val max2 = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }
}


/**
 * When 表达式
 */
fun main102() {
    val x = 3
    when (x) {
        1 -> println("x == 1")
        2 -> println("x == 2")
        else -> {
            println("x is neither 1 nor 2")
        }
    }

    /**
     * 如果其他分支都不满足条件将会求值 else 分支。
     * 如果 when 作为一个表达式使用，那么必须有 else 分支， 除非编译器能够检测出所有的可能情况都已经覆盖了，
     * 例如，对于 枚举（enum）类条目与密封（sealed）类子类型］。
     */
    val bit: Bit = Bit.ZERO
    val numericValue = when (bit) {
        Bit.ZERO -> 0
        Bit.ONE -> 1
        // 'else' is not required because all cases are covered
    }

    /**
     * In when statements, the else branch is mandatory in the following conditions:
     *  when has a subject of a Boolean, enum, or sealed type, or their nullable counterparts.
     *  branches of when don't cover all possible cases for this subject.
     */

    /**
     * To define a common behavior for multiple cases, combine their conditions in a single line with a comma:
     */
    when (x) {
        0, 1 -> println("x == 0 or x == 1")
        else -> println("otherwise")
    }

    /**
     * 可以用任意表达式（而不只是常量）作为分支条件
     */
    val s = "123"
    when (x) {
        s.toInt() -> println("s encodes x")
        else -> println("s does not encode x")
    }

    /**
     * 还可以检测一个值在（in）或者不在（!in）一个区间或者集合中：
     */
    val validNumbers = 1..9
//    val validNumbers = arrayOf(1, 2, 3, 4, 5)     //Array也可以
    when (x) {
        in 1..10 -> println("x is in the range")
        in validNumbers -> println("x is valid")
        !in 10..20 -> println("x is outside the range")
        else -> println("none of the above")
    }

    /**
     * 另一种选择是检测一个值是（is）或者不是（!is）一个特定类型的值。
     * 注意： 由于智能转换，你可以访问该类型的方法与属性而无需任何额外的检测。
     */
    fun hasPrefix(x: Any) = when(x) {
        is String -> x.startsWith("prefix")
        else -> false
    }

    /**
     * when 也可以用来取代 if-else if 链。
     * 如果不提供参数，所有的分支条件都是简单的布尔表达式，而当一个分支的条件为真时则执行该分支：
     */
    when {
//        x.isOdd() -> print("x is odd")
//        y.isEven() -> print("y is even")
//        else -> print("x+y is odd")
    }

    /**
     * 可以使用以下语法将 when 的主语（subject，译注：指 when 所判断的表达式）捕获到变量中：
     */
//    fun Request.getBody() =
//        when (val response = executeRequest()) {
//            is Success -> response.body
//            is HttpError -> throw HttpException(response.status)
//        }
}
enum class Bit {
    ZERO, ONE
}


/**
 * For 循环
 */
fun main103() {
    val ints = arrayOf(1, 2, 3)
    /**
     * for 循环可以对任何提供迭代器（iterator）的对象进行遍历，这相当于像 C# 这样的语言中的 foreach 循环。 for 的语法如下所示：
     * for (item in collection) print(item)
     */
    //for 循环体可以是一个代码块。
    for (item: Int in ints) {
        // ……
    }
    /**
     * 如上所述，for 可以循环遍历任何提供了迭代器的对象。这意味着：
     *  有一个成员函数或者扩展函数 iterator() 返回 Iterator<>：
     *  有一个成员函数或者扩展函数 next()
     *  有一个成员函数或者扩展函数 hasNext() 返回 Boolean。
     *
     * 这三个函数都需要标记为 operator。
     */


    /**
     * 如需在数字区间上迭代，请使用区间表达式:
     */
    for (i in 1..3) {
        print("$i ")
    }
    println()
    for (i in 6 downTo 0 step 2) {
        print("$i ")
    }
    println()


    /**
     * 对区间或者数组的 for 循环会被编译为并不创建迭代器的基于索引的循环。
     * 如果你想要通过索引遍历一个数组或者一个 list，你可以这么做：
     */
    val array = arrayOf("a", "b", "c")
    for (i in array.indices) {      //array.indices: IntRange
        print("${array[i]} ")
    }
    println()


    /**
     * 或者你可以用库函数 withIndex：
     */
    for ((index, value) in array.withIndex()) {     //array.withIndex(): Iterable<IndexedValue<T>>
        println("the element at $index is $value")
    }
}


/**
 * while 循环
 */
fun main104() {
    var x = 3
    while (x > 0) {
        x--
    }

//    do {
//        val y = retrieveData()
//    } while (y != null)         // y 在此处可见
}


/**
 * 循环中的 break 与 continue
 */
fun main105() {
    //在循环中 Kotlin 支持传统的 break 与 continue 操作符。参见返回与跳转。https://book.kotlincn.net/text/returns.html
}